﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Device.Location;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Controls;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Maps.Toolkit;
using IndustrialSmokeCalc.SmokeCalcWCF;
using Telerik.Windows.Controls;
using GestureEventArgs = Microsoft.Phone.Controls.GestureEventArgs;
using HeaderedItemsControl = Telerik.Windows.Controls.Primitives.HeaderedItemsControl;

namespace IndustrialSmokeCalc
{
    public partial class ChimneyMap : PhoneApplicationPage
    {
        private GeoCoordinate currentLocation;
        private MapLayer locationLayer;
        const int MIN_ZOOM_LEVEL = 5;
        const int MAX_ZOOM_LEVEL = 20;
        private ObservableCollection<ChimneyLocation> listChimney;
        private Location loc;
        private GeoCoordinate geoCoordinate;
        private Chimney SelectedChimney;
        private bool MessageBoxFired;

        public ChimneyMap()
        {
            InitializeComponent();
            this.PropertyChanged += LoadChimney_PropertyChanged;
            if(DataSingleton.Instance.MapAccessor == "measurement")
                this.chimneyMap.Tap += chimneyMap_Tap;

            listChimney = new ObservableCollection<ChimneyLocation>();
            MapExtensionsSetup(chimneyMap);
            LoadChimneyPushpin();
        }

        private void MapTapHandler(bool status)
        {
            if (status)
                this.chimneyMap.Tap -= chimneyMap_Tap;
            else this.chimneyMap.Tap += chimneyMap_Tap;
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            //MapTapHandler(false);
            //this.chimneyMap.Tap += chimneyMap_Tap;
            MessageBoxFired = false;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            //this.chimneyMap.Tap += chimneyMap_Tap;
            //listChimney = new ObservableCollection<ChimneyLocation>();
            //MapExtensionsSetup(chimneyMap);
            //LoadChimneyPushpin();
        }

        private void LoadChimney_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            DataContext = listChimney;
            StoredChimney.ItemsSource = null;
            StoredChimney.ItemsSource = listChimney;
            Dispatcher.BeginInvoke(ShowAllChimney);
        }

        private GeoCoordinate GetCurrentLocation()
        {
            Location loc = new Location();
            GeoCoordinate geoCoordinate = loc.GetCoordinate();
            double latitude = geoCoordinate.Latitude;
            double longitude = geoCoordinate.Longitude;
            return new GeoCoordinate(latitude, longitude);
        }

        private void LoadChimneyPushpin()
        {
            SmokeCalcClient client = new SmokeCalcClient();
            client.GetChimneyListCompleted += GetChimneyListCompleted;
            string param, value1, value2;
            if (DataSingleton.Instance.MapAccessor == "measurement")
            {
                param = "companyid";
                value1 = DataSingleton.Instance.CompanyId;
                value2 = "";
            }
            else
            {
                param = "userid";
                value1 = DataSingleton.Instance.UserId;
                value2 = DataSingleton.Instance.CompanyId;
            }
            client.GetChimneyListAsync(param, value1, value2);
        }

        private void GetChimneyListCompleted(object sender, GetChimneyListCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ShowExceptionMessage();
            }
            else if (e.Result.Count > 0)
            {
                listChimney = new ObservableCollection<ChimneyLocation>();
                foreach (var item in e.Result)
                {
                    Chimney chim = item;
                    ChimneyLocation chimney = new ChimneyLocation();
                    chimney.Id = chim.ChimneyId;
                    chimney.Name = chim.ChimneyName;
                    chimney.Description = chim.ChimneyDescription;
                    chimney.GeoCoordinate = new GeoCoordinate(chim.ChimneyLatitude, chim.ChimneyLongitude);
                    listChimney.Add(chimney);
                }
                NotifyPropertyChanged();
            }
            else
            {
                MessageBoxResult btn = MessageBox.Show("Tidak terdapat cerobong.\r\nTambahkan cerobong terlebih dahulu.", "Peringatan", MessageBoxButton.OK);
                if (btn == MessageBoxResult.OK)
                {
                    ShowCurrentLocation();   
                }
            }
        }

        private void ShowCurrentLocation()
        {
            currentLocation = GetCurrentLocation();
            chimneyMap.SetView(currentLocation, 17, MapAnimationKind.Parabolic);
            Ellipse myCircle = new Ellipse();
            myCircle.Fill = new SolidColorBrush(new Color(){ A=255, R=124, G=252, B=0 });
            myCircle.Stroke = new SolidColorBrush(new Color() { A=255, R=0, G=0, B=0 });
            myCircle.StrokeThickness = 2;
            myCircle.Height = 20;
            myCircle.Width = 20;
            myCircle.Opacity = 50;

            // Create a MapOverlay to contain the circle.
            MapOverlay myLocationOverlay = new MapOverlay();
            myLocationOverlay.Content = myCircle;
            myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
            myLocationOverlay.GeoCoordinate = currentLocation;

            // Delete last added MapLayer
            chimneyMap.Layers.Remove(locationLayer);

            // Create a MapLayer to contain the MapOverlay.
            locationLayer = new MapLayer();
            locationLayer.Add(myLocationOverlay);

            // Add the MapLayer to the Map.
            chimneyMap.Layers.Add(locationLayer);
        }

        private void ShowAllChimney()
        {
            LocationRectangle locationRectangle = LocationRectangle.CreateBoundingRectangle(from chimney in listChimney select chimney.GeoCoordinate);
            chimneyMap.SetView(locationRectangle, new Thickness(50, 50, 100, 50), MapAnimationKind.Parabolic);
        }

        private void CurrentLocation_Click(object sender, EventArgs e)
        {
            ShowCurrentLocation();
        }

        private void HybridMode_Click(object sender, EventArgs e)
        {
            chimneyMap.CartographicMode = MapCartographicMode.Hybrid;
        }

        private void RoadMode_Click(object sender, EventArgs e)
        {
            chimneyMap.CartographicMode = MapCartographicMode.Road;
        }

        private void ZoomIn_Click(object sender, EventArgs e)
        {
            if (chimneyMap.ZoomLevel < MAX_ZOOM_LEVEL)
            {
                chimneyMap.ZoomLevel++;
            }
        }

        private void ZoomOut_Click(object sender, EventArgs e)
        {
            if (chimneyMap.ZoomLevel > MIN_ZOOM_LEVEL)
            {
                chimneyMap.ZoomLevel--;
            }
        }

        private void MapExtensionsSetup(Map map)
        {
            ObservableCollection<DependencyObject> children = MapExtensions.GetChildren(map);
            var runtimeFields = this.GetType().GetRuntimeFields();

            foreach (DependencyObject i in children)
            {
                var info = i.GetType().GetProperty("Name");

                if (info != null)
                {
                    string name = (string)info.GetValue(i);

                    if (name != null)
                    {
                        foreach (FieldInfo j in runtimeFields)
                        {
                            if (j.Name == name)
                            {
                                j.SetValue(this, i);
                                break;
                            }
                        }
                    }
                }
            }
        }

        private async void AddedPushPin_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            Style nameStyle = new Style(typeof(RadTextBox));
            nameStyle.Setters.Add(new Setter(RadTextBox.HeaderProperty, "Nama cerobong"));

            Style descriptionStyle = new Style(typeof(RadTextBox));
            descriptionStyle.Setters.Add(new Setter(RadTextBox.HeaderProperty, "Deskripsi cerobong"));
            
            InputPromptSettings settings = new InputPromptSettings();
            settings.Field1Mode = InputMode.Text;
            settings.Field1Style = nameStyle;
            settings.Field2Mode = InputMode.Text;
            settings.Field2Style = descriptionStyle;

            string messageTitle = "Tambahkan Cerobong";
            string message = "Masukkan data cerobong yang akan ditambahkan.";

            InputPromptClosedEventArgs args = await RadInputPrompt.ShowAsync(settings, messageTitle, MessageBoxButtons.OKCancel, message);

            int buttonIndex = args.ButtonIndex;

            if (buttonIndex == 0)
            {
                Pushpin pushpin = sender as Pushpin;
                SelectedChimney = new Chimney();
                SelectedChimney.CompanyId = DataSingleton.Instance.CompanyId;
                SelectedChimney.ChimneyName = args.Text;
                SelectedChimney.ChimneyDescription = args.Text2;
                SelectedChimney.ChimneyLatitude = pushpin.GeoCoordinate.Latitude;
                SelectedChimney.ChimneyLongitude = pushpin.GeoCoordinate.Longitude;

                //DataSingleton.Instance.ChimneyId = AddedChimney.ChimneyLatitude.ToString();
                //NavigationService.Navigate(new Uri("/Form.xaml", UriKind.Relative));
                InsertChimney(SelectedChimney);
            }
            else
            {
                ShowAllChimney();
            }
        }

        private void InsertChimney(Chimney chimney)
        {
            SmokeCalcClient client = new SmokeCalcClient();
            client.AddChimneyCompleted += AddChimneyCompleted;
            client.AddChimneyAsync(chimney.CompanyId, chimney.ChimneyName, chimney.ChimneyDescription,
                chimney.ChimneyLatitude, chimney.ChimneyLongitude);
        }

        private void AddChimneyCompleted(object sender, AddChimneyCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ShowExceptionMessage();
            }
            else if (e.Result == "sukses")
            {
                GetChimneyId(SelectedChimney.ChimneyLatitude, SelectedChimney.ChimneyLongitude);
            }
        }

        private void GetChimneyId(double latitude, double longitude)
        {
            SmokeCalcClient client = new SmokeCalcClient();
            client.GetChimneyIdCompleted += GetChimneyIdCompleted;
            client.GetChimneyIdAsync(latitude.ToString(), longitude.ToString());
        }

        private void GetChimneyIdCompleted(object sender, GetChimneyIdCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ShowExceptionMessage();
            }
            else
            {
                DataSingleton.Instance.ChimneyId = e.Result;
                //DataSingleton.Instance.ChimneyId = e.Result + " " + SelectedChimney.ChimneyLatitude + " " + SelectedChimney.ChimneyLongitude;
                if(DataSingleton.Instance.MapAccessor == "measurement")
                    NavigationService.Navigate(new Uri("/Form.xaml", UriKind.Relative));
                else NavigationService.Navigate(new Uri("/History.xaml", UriKind.Relative));
            }
        }

        private void StoredPushpin_Tap(object sender, GestureEventArgs e)
        {
            //this.chimneyMap.Tap -= chimneyMap_Tap;

            Pushpin pushpin = sender as Pushpin;
            ChimneyLocation chimney = GetTappedChimney(pushpin.GeoCoordinate);
            SelectedChimney = new Chimney();
            SelectedChimney.ChimneyLatitude = chimney.GeoCoordinate.Latitude;
            SelectedChimney.ChimneyLongitude = chimney.GeoCoordinate.Longitude;
            string message = "";
            if (DataSingleton.Instance.MapAccessor == "measurement")
            {
                message = String.Format("Apakah anda yakin untuk memilih cerobong ini?\r\nNama\t  =  {0}" +
                                           "\r\nDeskripsi\t  =  {1}", chimney.Name, chimney.Description);    
            }
            else
            {
                message = String.Format("Apakah anda yakin untuk melihat histori cerobong ini?\r\nNama\t  =  {0}" +
                                           "\r\nDeskripsi\t  =  {1}", chimney.Name, chimney.Description);  
            }
            
            string title = "Pilih Cerobong";
            MessageBoxResult result = MessageBox.Show(message, title, MessageBoxButton.OKCancel);
            if (result == MessageBoxResult.OK)
            {
                GetChimneyId(SelectedChimney.ChimneyLatitude, SelectedChimney.ChimneyLongitude);
            }
            else
            {
                MessageBoxFired = true;
                //AddedPushPin.Visibility = Visibility.Collapsed;
            }
        }

        private ChimneyLocation GetTappedChimney(GeoCoordinate geoCoordinate)
        {
            foreach (var item in listChimney)
            {
                if (item.GeoCoordinate == geoCoordinate)
                {
                    return item;
                }
            }
            return null;
        }

        private void chimneyMap_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            //if (!MessageBoxFired)
            {
                geoCoordinate = chimneyMap.ConvertViewportPointToGeoCoordinate(e.GetPosition(chimneyMap));

                loc = new Location();
                loc.GetAddress(geoCoordinate.Latitude.ToString(), geoCoordinate.Longitude.ToString());
                loc.PropertyChanged += loc_PropertyChanged;   
            }
        }

        private void loc_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            AddedPushPin.GeoCoordinate = geoCoordinate;
            AddedPushPin.Content = loc.Street;
            AddedPushPin.Visibility = Visibility.Visible;
        }

        private void ShowExceptionMessage()
        {
            MessageBox.Show("Tidak dapat melakukan koneksi ke server.\r\nCoba periksa koneksi internet anda.");
            NavigationService.Navigate(new Uri("/Menu.xaml", UriKind.Relative));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}